package com.alibaba.citrus.ots.sales.plan.aspect;

import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.exception.RepositoryException;
import com.alibaba.citrus.ots.common.lock.RedisLock;
import com.alibaba.citrus.ots.sales.plan.CustomLockKey;
import com.alibaba.citrus.ots.sales.plan.annotation.CommonRedisLock;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.message.ErrorMessage;
import com.alibaba.cz.base.tool.result.Results;
import com.epoch.app.bcots.contants.BcOtsConstants;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 并发日志切面
 *
 * @author: suqing.tjf
 * @create: 2021年12月19日17:04:04
 **/
@Aspect
@Component
public class RedisLockAspect {

    private static final Log log = Log.getLogger(RedisLockAspect.class);

    @Pointcut("@annotation(com.alibaba.citrus.ots.sales.plan.annotation.CommonRedisLock)")
    public void serviceAspect() {
    }

    /**
     * 获取注解参数，记录日志
     *
     * @param joinPoint 切入点参数
     */
    @Around(value = "serviceAspect()")
    public Object doService(ProceedingJoinPoint joinPoint) {
        Object resp = null;
        Signature signature = joinPoint.getSignature();
        String targetName = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        MethodSignature methodSignature = (MethodSignature)signature;
        Method targetMethod = methodSignature.getMethod();

        // 注解中配置的优先级更高
        CommonRedisLock annotation = targetMethod.getAnnotation(CommonRedisLock.class);
        String customLockCondition = annotation.customLockCondition();
        Object[] args = joinPoint.getArgs();
        if (StringUtils.isBlank(customLockCondition) && args != null && args.length > 0) {
            for (Object arg : args) {
                if (arg instanceof CustomLockKey) {
                    customLockCondition = ((CustomLockKey) arg).getCustomLockCondition();
                }
            }
        }
        if (StringUtils.isBlank(customLockCondition)) {
            throw new FacadeException(ErrorMessage.code("OTS-02-007-00-16-002"));
        }
        String redisKey = annotation.redisLockPrefix() + customLockCondition;
        log.info(targetName + "." + methodName + "_预先生成的RedisKey:{}", redisKey);
        try (RedisLock lock = new RedisLock(BcOtsConstants.REDIS_CACHE_CODE(), redisKey, annotation.waitTime(), annotation.holdTime())) {
            boolean locked = lock.lock();
            if (!locked) {
                log.error(targetName + "#" + methodName + ".getLock.fail RedisKey=" + redisKey);
                return Results.fail("OTS-02-007-00-16-001", "正在操作中，请稍后重试");
            }
            log.info(targetName + "." + methodName + "_成功获取到redis锁:{}", redisKey);
            // 方法执行
            resp = joinPoint.proceed();
        } catch (FacadeException | RepositoryException e) {
            log.error(targetName + "#" + methodName + "_fail ", e);
            throw new FacadeException(e.getErrorCode(), e.getErrorMessage());
        } catch (Throwable throwable) {
            log.error(targetName + "#" + methodName + "_fail ", throwable);
            throw new FacadeException(ErrorMessage.code("OTS-02-007-00-16-999"));
        }
        return resp;
    }
}


